package cate.game.pvp.eliterace.simulator;

import cate.game.framework.advanced.AdvancedByteAttributes;
import cate.game.framework.advanced.AdvancedLongAttributes;
import cate.game.pvp.eliterace.data.*;
import cate.game.pvp.eliterace.handler.*;
import cate.game.pvp.eliterace.timer.EliteRaceTimerTask.Settings;
import com.google.common.collect.Lists;
import org.springframework.util.CollectionUtils;

import java.util.Comparator;
import java.util.List;
import java.util.Objects;
import java.util.function.Supplier;

import static cate.game.event.eliterace.EliteRaceTimerEvent.EventType.RANK_SWITCH;
import static cate.game.pvp.eliterace.data.EliteRaceKV.OP_SKIP_SEASON;

public class BothEliteRaceRankRwdSimulator extends EliteRaceSimulator {

    private final Supplier<EliteRaceRankHandler> rankHandlerSupplier;
    private final Supplier<EliteRaceExcelQueryOperation> excelQueryOperationSupplier;

    public BothEliteRaceRankRwdSimulator(Supplier<EliteRaceKV> kvSupplier,
                                         Supplier<EliteRaceRecordOperation> recordOperationSupplier,
                                         Supplier<EliteRacePsOperation> psOperationSupplier,
                                         Supplier<EliteRaceFightOperation> fightOperationSupplier,
                                         Supplier<EliteRaceRankRwdOperation> rankRwdOperationSupplier,
                                         Supplier<EliteRaceBetOperation> betOperationSupplier,
                                         Supplier<EliteRaceRankHandler> rankHandlerSupplier,
                                         Supplier<EliteRaceExcelQueryOperation> excelQueryOperationSupplier,
                                         Supplier<EliteRaceVideoOperation> videoOperationSupplier) {
        super(
                kvSupplier,
                recordOperationSupplier,
                psOperationSupplier,
                fightOperationSupplier,
                rankRwdOperationSupplier,
                betOperationSupplier,
                videoOperationSupplier
        );

        this.rankHandlerSupplier = Objects.requireNonNull(rankHandlerSupplier);
        this.excelQueryOperationSupplier = Objects.requireNonNull(excelQueryOperationSupplier);
    }

    @Override
    public boolean isMatch(Settings settings) {
        return settings.getEventType() == RANK_SWITCH;
    }

    @Override
    public boolean runWith(Settings settings) {
        AdvancedByteAttributes opAttributes = getOpAttributes();
        AdvancedLongAttributes attributes = getAttributes();
        if (opAttributes.hasAttribute(OP_SKIP_SEASON)) {
            getKV().setSpec(settings.getSpec());
            attributes.setAttribute(settings.getEventType().getFlag());
            return true;
        }
        if (attributes.hasAttribute(settings.getEventType().getFlag())) {
            return true;
        }
        EliteRaceKV kv = getKV();
        kv.setSpec(settings.getSpec());

        EliteRacePsOperation psOperation = getPsOperation();
        List<EliteRacePs> sortedPs = psOperation.getSortedPs(
                Comparator.comparing(EliteRacePs::getOpponent, Comparator.comparing(EliteRaceOpponent::getWinCount, Comparator.reverseOrder()))
                        .thenComparing(EliteRacePs::getOpponent, Comparator.comparing(EliteRaceOpponent::getPoints, Comparator.reverseOrder()))
        );

        if (CollectionUtils.isEmpty(sortedPs)) {
            attributes.setAttribute(settings.getEventType().getFlag());
            return true;
        }

        getRankHandler().clear();

        sortedPs.stream()
                .map(EliteRaceRank::of)
                .forEach(getRankHandler()::update);

        getRankHandler().sortRankThenUpdateIndex();

        List<EliteRaceRankRwd> rwdList = Lists.newArrayList();
        EliteRaceExcelQueryOperation excelQueryOperation = getExcelQueryOperation();

        for (int i = 0; i < sortedPs.size(); i++) {
            EliteRacePs ps = sortedPs.get(i);
            int rank = getRankHandler().getIndex(ps.getUid());
            EliteRaceRankRwd rwd = EliteRaceRankRwd.of(
                    ps.getUid(),
                    kv.getSeason(),
                    ps.getOpponent().getSnapshot().base.srvId,
                    rank,
                    excelQueryOperation.getRankReward(rank)
            );
            rwdList.add(rwd);
        }

        EliteRaceRankRwdOperation rankRwdOperation = getRankRwdOperation();
        rankRwdOperation.upsert(rwdList);

        rankRwdOperation.lamp(sortedPs.get(0).getOpponent().getSnapshot());

        attributes.setAttribute(settings.getEventType().getFlag());
        return true;
    }

    private EliteRaceRankHandler getRankHandler() {
        return Objects.requireNonNull(rankHandlerSupplier.get());
    }

    private EliteRaceExcelQueryOperation getExcelQueryOperation() {
        return Objects.requireNonNull(excelQueryOperationSupplier.get());
    }
}
